package io.github.aaron.commonadmin.base.util;

import org.apache.commons.collections4.MapUtils;
import org.apache.commons.io.IOUtils;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
import org.apache.hc.core5.util.TimeValue;
import org.apache.hc.core5.util.Timeout;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestClient;
import org.springframework.web.util.UriBuilder;
import java.io.IOException;
import java.net.URI;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author: AaronF
 * @Date: 2025/10/22/22:28
 * @Description: http 连接池工具类，使用apache http client，
 */
public class HttpPoolUtils {

    public static void main(String[] args) {
//        Map<String,Object> paramMap = new HashMap<>();
//        paramMap.put("type","其他");
//        paramMap.put("level",1);
//        ResponseEntity<Test> stringResponseEntity = HttpPoolUtils.doGet4Json("https://api.timelessq.com/joke",paramMap, Test.class);
//        System.out.println(stringResponseEntity);
//        System.out.println("是");
        Map<String,String> headers = new HashMap<>();
        headers.put(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN,"test");
        Test test = new Test();
        test.setErrmsg("aa");
        test.setErrno(1);
        ResponseEntity<String> stringResponseEntity = doPost("https://httpbin.org/post");
        System.out.println(stringResponseEntity);
    }

    /**
     * http客户端
     */
    private static final CloseableHttpClient HTTP_CLIENT;
    /**
     * rest请求门面
     */
    public static final RestClient REST_CLIENT;
    /**
     * tcp连接池最大连接数
     */
    private static final int TCP_MAX_TOTAL = 300;
    /**
     * 单路由上限
     */
    private static final int MAX_PER_ROUTE = 50;
    /**
     * tcp连接超时时间
     */
    private static final int TCP_CONNECTION_TIME_OUT_SECOND = 10;
    /**
     * 读取超时时间
     */
    private static final int HTTP_RESPONSE_TIME_OUT_SECOND = 20;
    /**
     * tcp连接回收时间
     */
    private static final int TCP_EVICT_IDLE_SECOND = 30;

    private static final String EMPTY_JSON = "{}";

    static {
        // apache http client连接配置
        PoolingHttpClientConnectionManager connMgr = new PoolingHttpClientConnectionManager();
        connMgr.setMaxTotal(TCP_MAX_TOTAL);
        connMgr.setDefaultMaxPerRoute(MAX_PER_ROUTE);

        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectionRequestTimeout(Timeout.ofSeconds(TCP_CONNECTION_TIME_OUT_SECOND))
                .setResponseTimeout(Timeout.ofSeconds(HTTP_RESPONSE_TIME_OUT_SECOND))
                .build();

        // 定义apache http client
        HTTP_CLIENT = HttpClients.custom()
                .setConnectionManager(connMgr)
                .setDefaultRequestConfig(requestConfig)
                // tcp连接回收时间
                .evictIdleConnections(TimeValue.ofSeconds(TCP_EVICT_IDLE_SECOND))
                .build();

        // 自带json解析器，如需要其他解析器通过 .messageConverters() 添加
        REST_CLIENT = RestClient.builder()
                .requestFactory(new HttpComponentsClientHttpRequestFactory(HTTP_CLIENT))
                .build();

        // 注册钩子函数程序退出时关闭http客户端
        Runtime.getRuntime().addShutdownHook(new Thread(() -> IOUtils.closeQuietly(HTTP_CLIENT)));
    }

    public static ResponseEntity<String> doGet(String url) {
        return doGet(url,Collections.emptyMap(),Collections.emptyMap());
    }

    public static ResponseEntity<String> doGet(String url, Map<String, Object> queryParams) {
        return doGet(url,queryParams,Collections.emptyMap());
    }

    public static ResponseEntity<String> doGet(String url, Map<String, Object> queryParams,Map<String,String> headers) {
        return REST_CLIENT.get()
                .uri(url,uriBuilder -> buildUri(uriBuilder,queryParams))
                .headers(httpHeaders -> addHeader(httpHeaders,headers))
                .exchange((request, response) -> handleResponse(response,String.class));
    }

    public static <T> ResponseEntity<T> doGet4Json(String url, Class<T> clazz) {
        return doGet4Json(url, Collections.emptyMap(),Collections.emptyMap(),clazz);
    }

    public static <T> ResponseEntity<T> doGet4Json(String url, Map<String, Object> queryParams, Class<T> clazz) {
        return doGet4Json(url, queryParams,Collections.emptyMap(),clazz);
    }

    public static <T> ResponseEntity<T> doGet4Json(String url, Map<String, Object> queryParams,Map<String,String> headers, Class<T> clazz) {
        return REST_CLIENT.get()
                .uri(url,uriBuilder -> buildUri(uriBuilder,queryParams))
                .accept(MediaType.APPLICATION_JSON)
                .headers(httpHeaders -> addHeader(httpHeaders,headers))
                .exchange((request, response) -> handleResponse(response,clazz));
    }

    public static ResponseEntity<String> doPost(String url){
        return doPost(url,EMPTY_JSON,Collections.emptyMap());
    }

    public static ResponseEntity<String> doPost(String url,Object body){
        return doPost(url,body,Collections.emptyMap());
    }

    public static ResponseEntity<String> doPost(String url,Object body,Map<String,String> headers){
        return REST_CLIENT.post()
                .uri(url)
                .contentType(MediaType.APPLICATION_JSON)
                .headers(httpHeaders -> addHeader(httpHeaders,headers))
                .body(body)
                .exchange((request, response) -> handleResponse(response,String.class));
    }

    public static <T> ResponseEntity<T> doPost4Json(String url, Class<T> clazz){
        return doPost4Json(url,EMPTY_JSON,Collections.emptyMap(),clazz);
    }

    public static <T> ResponseEntity<T> doPost4Json(String url,Object body, Class<T> clazz){
        return doPost4Json(url,body,Collections.emptyMap(),clazz);
    }

    public static <T> ResponseEntity<T> doPost4Json(String url,Object body,Map<String,String> headers, Class<T> clazz){
        return REST_CLIENT.post()
                .uri(url)
                .contentType(MediaType.APPLICATION_JSON)
                .accept(MediaType.APPLICATION_JSON)
                .headers(httpHeaders -> addHeader(httpHeaders,headers))
                .body(body)
                .exchange((request, response) -> handleResponse(response,clazz));
    }

    private static void addHeader(HttpHeaders httpHeaders,Map<String, String> headers) {
        if (MapUtils.isNotEmpty(headers)){
            headers.forEach(httpHeaders::add);
        }
    }

    private static URI buildUri( UriBuilder uriBuilder,Map<String, Object> queryParams) {
        if (MapUtils.isNotEmpty(queryParams)){
            queryParams.forEach(uriBuilder::queryParam);
        }
        return uriBuilder.build();
    }

    private static <T> ResponseEntity<T> handleResponse(RestClient.RequestHeadersSpec.ConvertibleClientHttpResponse response,Class<T> type) throws IOException {
        if (response.getStatusCode().isError()) {
            // 失败响应不做解析
            return ResponseEntity.status(response.getStatusCode()).body(null);
        }
        return ResponseEntity.ok(response.bodyTo(type));
    }


}
